from yant import *

class SRAnalyzer:

    def __init__(self, lex, f, g):
        self._f = f
        self._g = g
        self._stack = [(SOS, '')]
#        self._stack = [('$', '$')]
        self._lex = lex

    def _printState(self, printSymbol = True, printAttrs = False):
        symbols = map(lambda x : x[0], self._stack)
        attrs   = map(lambda x : x[1], self._stack)
        if printSymbol:
            print map(str, symbols), ' : ',

        nexttoken = self._lex.nextToken()
        self._lex.pushToken(nexttoken)

        symbol, attr = nexttoken
        print "'%s'" % symbol, '...'

    def _process(self):
        self._printState()

        curtoken = self._stack[-1]
        nexttoken = self._lex.nextToken();

        cursymbol , curattr  = curtoken
        nextsymbol, nextattr = nexttoken

        act = self._f(cursymbol, nextsymbol)
        if act == SHIFT:
            print 'SHIFT:', '%s (%s)' % nexttoken

            self._stack.append(nexttoken)
        elif act == REDUCE:
            stacksymbols = map(lambda x: x[0], self._stack)
            production = self._g(stacksymbols)
            print 'REDUCE:', str(production)
            
            reducelen = production.getReduceLen()

            reducedtokens  = self._stack[-reducelen:]
            self._stack = self._stack[:-reducelen]

            newtoken = production.reduce(reducedtokens, self._lex.getLine())
            self._stack.append(newtoken)

            self._lex.pushToken(nexttoken)
        elif act == ACCEPT:
            self._lex.pushToken(nexttoken)
            print 'ACCEPTED!'
            print
            return True
        elif act == ERROR:
            raise Exception('Syntax error')
        else:
            raise Exception('Undefined action')
        print
        return False

    def run(self):
        while not self._process():
            pass

        assert(len(self._stack) == 2)
        nextsymbol, _ = self._lex.nextToken();
        assert(nextsymbol == EOS)
        
        print 'Result:'
        print map(str, self._stack[1])

        return self._stack[1][1]

class StubLex:
    def __init__(self, token_list):
        self._list = token_list

    def nextToken(self):
        return self._list.pop(0)

    def pushToken(self, token):
        self._list = [token] + self._list

    def __str__(self):
        return str(self._list)

class PushLexer:
    def __init__(self, lex):
        self._lex = lex
        self._stack = []

    def nextToken(self):
        if self._stack:
            return self._stack.pop()
        else:
            return self._lex.nextToken()

    def pushToken(self, token):
        self._stack = self._stack + [token]

    def getLine(self):
        return self._lex.getLine()

class KeywordLexer:
    def __init__(self, lex, keywords):
        self._lex = lex
        self._keywords = keywords

    def nextToken(self):
        token = self._lex.nextToken()
        t, v = token
        if (t == TSymbol('ID')) and (v in self._keywords):
            return TSymbol(v), v
        else:
            return token

    def pushToken(self, token):
        self._lex.pushToken(token)

    def getLine(self):
        return self._lex.getLine()

class CommentFilterLexer:
    def __init__(self, lex):
        self._lex = lex

    def nextToken(self):
        token = self._lex.nextToken()
        t, v = token
        if t == TSymbol('COMMENT'):
            return self.nextToken()
        else:
            return token

    def pushToken(self, token):
        self._lex.pushToken(token)
        
    def getLine(self):
        return self._lex.getLine()
